컴퓨팅 자원
개요
파드에 사용할 수 있는 자원 중 가장 직관적인 것 중 하나는 프로세스가 실행되는데 필요한 자원일 것이다.
그리고 기본적으로 프로세스가 돌아가는데 있어 폰노이만 아키텍쳐에서 필수적으로 필요한 것은 cpu, 메모리이다.
쿠버네티스에서는 그러한 자원들을 연산 자원(computing resource)이라고 부른다.
이 둘이 어떻게 설정될 수 있고, 어떤 식으로 할당되는지 이 문서에서 자세히 다룬다.
추후에 OS에 대해 자세히 정리하게 된다면 이 문서의 상당 부분들이 다른 곳으로 옮겨질 수 있다.
이 개념들은 스케줄링과도 밀접한 연관성을 맺기 때문에 추후 문서 내용이 많이 달라질 수 있다.
CPU
CPU는 연산을 수행하는 프로세서 자원이다.
즉, 메모리처럼 몇 바이트만 써라, 어느 공간만 차지해라 할 수 있는 개념이 아니란 말이다.
그렇다면 CPU의 사용량은 어떻게 측정하는가?
결론만 먼저 말하자면 CPU는 단위 시간 동안 어떤 프로세스의 명령을 얼마나 실행했는지를 기준으로 사용률을 측정한다.
CFS(Completely Fair Scheduling)
CPU는 프로세스에 적힌 명령을 읽어서 그 명령을 실행하는데, 여러 프로세스와 스레드에서 주어진 명령을 번갈아가면서 수행한다.
CPU가 어떤 명령을 수행해야 하는지 순서나 우선순위를 정해서 동작하게 하는 것을 CPU 스케줄링이라고 부른다.
그리고 이 스케줄링에는 다양한 알고리즘 기법이 있는데, 현대 리눅스 기준으로 사용되는 알고리즘은 CFS이다.
이 알고리즘은 선점형 스케줄링(우선순위에 따라 스케줄링)의 일종으로, 모든 프로세스가 단위 시간 내에 한번이라도 CPU 연산을 수행할 수 있도록 한다는 특징을 가지고 있다.
관련 자료 찾아넣기
https://blog.outsider.ne.kr/1653
https://popappend.tistory.com/132
CPU requests
CPU limits
메모리
https://blog.naver.com/alice_k106/221676471427
https://dev.to/danielepolencic/memory-requests-and-limits-in-kubernetes-40ep
메모리 requests
메모리 limits
cpu
여기에서 cpu의 단위는 무엇인가?
하나의 유닛 단위를 가지는데, 이것은 하나의 물리적 코어, 혹은 가상 코어를 말한다.
이건 노드가 무엇인가에 따라 다를 것이다.
이때 소수점으로 요청을 할 수도 있다.
가령 0.5
를 쓰는 것은 1.0
의 절반을 나타낸다.
그리고 이 단위는 밀리 단위로도 나눌 수 있어서, 0.5
는 사실 500m
을 뜻하기도 한다.
항상 절대적인 총량을 명시해야 한다.
그래서 노드가 몇개의 cpu를 가지고 있던 간 이 값이 나타내는 단위는 항상 동일하다.
최소 단위는 1m
로, 이보다 낮으면 에러가 난다.
그래서 소수점을 이용할 바에는 m을 쓰자.
memory
메모리는 기본으로 바이트 단위인데, 다양한 방식으로 또 명시할 수 있다.
128974848, 129e6, 129M, 128974848000m, 123Mi
이 값들은 대충 같은 값들이다.
조심할 건 m
은 밀리 바이트를 의미하지만 M
은 메가 바이트를 의미한다는 것이다!
근데 cpu와 memory에 대한 limit 동작이 조금 다르다.
cpu에 대해서 프로세스가 제한치를 넘기면, 그냥 컨테이너가 cpu에 그 이상 접근하는 걸 막는다.
그래서 커널에 의해 막힌다고 보면 된다.
그러나 메모리는 OOM이 난다.
그래서 커널이 그냥 프로세스를 종료시켜버린다.
다만 커널이 메모리 압박을 감지할 때 일어나는 현상으로, 여분 메모리가 있는 상황인데 limit을 넘었다고 갑자기 종료시키는 것은 아니다.
그래서 사실 메모리에 대해서 limit을 넘긴다는 것은, 종료될 수도 있다 정도의 의미이다.
이런 방식은 사실 메모리에 대한 엄밀한 예측성을 떨어뜨린다.
물론 함부로 프로세스가 죽는 게 좋은 건 아니라고 해도, 명확하게 이만큼 쓰라 지정했는데 이를 넘기는 건 예측이 힘들다.
메모리에 대한 더 완벽한 제어를 위한 기능이 도입 중이나, 큰 진척은 없다.
만약 제한을 명시하고, 요청을 명시하지 않은 상태라 해보자.
근데 여기에 적용 시간 매커니즘도 그다지 없는 상태라면, 쿠버네티스는 제한의 값을 요청 값으로 복사해서 사용한다.
자원이 쓰이는 곳
그리고 kubelet이 컨테이너 런타임에 한 컨테이너에 얼마나 자원을 사용할 수 있는지 설정해줄 때도 쓰인다.
구체적으로는 cgroups를 이용한다.
cpu 리밋은 컨테이너가 사용하는 cpu 시간에 대한 최대 천장이다.
타임슬라이스 기반으로 cpu 유닛을 재기 대문.
만약 리밋을 넘긴다면 커널은 cgroups가 실행을 허용하기 전까지 기다려준다.
요청은 사실 가중치를 정의한다.
즉, 컨테이너가 하나만 돌아가고 잇는 상태면 사실 이 놈이 cpu를 다 먹고 있는 것이다.
같은 값으로 컨테이너가 두개 있으면 사이 좋게 노날 것이다.
컨테이너들의 값은 가중치로서 따지기 때문에, 사실 cpu를 먹고 있는 시간을 의미하는 것이다.
그럼 같은 값이어도 사실 컨테이너가 늘어나면 사용량이 달라지겠네?
메모리 요청은 파드 스케줄링에 쓰인다.
cgroups v2에서는 memory.min, memory.low의 힌트로 쓰인다.
리밋은 cgroup의 limit이다.
컨테이너가 제한보다 더 높이 쓰려고 하면, 리눅스 커널의 oom 하위시스템이 동작한다.
메모리를 할당받으려는 컨테이너 내부의 프로세스를 몇 개 지우려고 하는 방식이다.
근데 지워야 할 게 PID 1, 즉 컨테이너 메인 프로세스면 쿠버네티스에서는 컨테이너 자체를 재시작시켜준다.
메모리 제한은 메모리 기반 emptyDir에도 적용된다.
kubelet이 tmpfs를 local ephemeral이 아니라 메모리로 인식하기 때문이다.
그러면 emptydir을 여러 컨테이너가 쓰고 있으면 어케 인식됨? 두 컨테이너가 많이 사용한다 나오나?
emptydir에 sizeLimit
을 걸라.
없으면 메모리 제한에 걸린다.
requests만 있는 파드라면 정말 노드 메모리 다쓰는 수가 있다.
그리고 노드 스케줄링 자체는 request만 기반으로 일어난다.
메모리 거의 다쓴 노드에 파드 넣으면 어케 되냐? 그놈이 적당히 쓰는 줄 알았는데 갑자기 많이 쓰면?
emptydir은 위험한게 언어 레벨의 관리가 안 된다는 것이다.
그래서 유저가 멋대로 할당해버려서 가비지 컬렉션도 기대할 수 없다.
노드에 메모리가 적어도 쿠버가 알아서 회수해줄 수도 없다.
노드 메모리 자체가 부족해지면, 축ㅊㄹ된다.
cpu 값이 늘어난다고 없애버리진 않는데도..
ResourceQuota로 클러스터, 네임스페이스 차원의 메모리 제한을 하자.
여기에 LimitRange를 지정하는 것도 하나의 좋은 방법이다.
아니면 어드미션 정책을 지정하자.
allocatable
kubelet 설정
관련 문서
이름 | noteType | created |
---|